project(
  'xnvme',
  'c',
  version: '0.6.0',
  license: 'APACHE',
  default_options: [
    'c_std=gnu11',
    'warning_level=2',
    'buildtype=release',
    'default_library=both',
    'b_staticpic=true'
# This seems broken on Windows
#    'b_lto=true',
  ],
  meson_version: '>=0.58'
)
pconf = import('pkgconfig')

#
# Pre-flight check, operating system and compiler arguments
#
system_support = ['freebsd', 'linux', 'windows', 'darwin']
system = host_machine.system()
message('host_machine.system:', system)
if not system_support.contains(system)
    error('Unsupported system type "@0@"'.format(exec_env))
endif
foreach sys : system_support
    set_variable('is_' + sys, system == sys)
endforeach

is_centos7 = run_command('cat', '/etc/os-release', check: false).stdout().contains('CentOS Linux 7')

cc = meson.get_compiler('c')
cc_flags = [
  '-Wno-missing-braces',
]
add_project_arguments(
  cc.get_supported_arguments(cc_flags),
  language: 'c'
)

prog_python = import('python').find_installation('python3')
message('python.language_version:', prog_python.language_version())

#xnvmelib_libdir = 'lib'
xnvmelib_libdir = get_option('libdir')

#
# The project itself
#
project_version_major = meson.project_version().split('.')[0]
project_version_minor = meson.project_version().split('.')[1]
project_version_patch = meson.project_version().split('.')[2]

#
# Configuration
#
conf_data = configuration_data()
conf_data.set('XNVME_VERSION_MAJOR', project_version_major)
conf_data.set('XNVME_VERSION_MINOR', project_version_minor)
conf_data.set('XNVME_VERSION_PATCH', project_version_patch)

conf_data.set('XNVME_DEBUG_ENABLED', get_option('buildtype') == 'debug')

conf_data.set('XNVME_BE_RAMDISK_ENABLED', get_option('be_ramdisk'))

conf_data.set('XNVME_BE_WINDOWS_ENABLED', is_windows)
conf_data.set('XNVME_BE_WINDOWS_FS_ENABLED', is_windows)
conf_data.set('XNVME_BE_WINDOWS_ASYNC_ENABLED', is_windows)

conf_data.set('XNVME_BE_LINUX_ENABLED', is_linux)
conf_data.set('XNVME_BE_LINUX_BLOCK_ENABLED', is_linux ? cc.has_header('linux/blkzoned.h') : false)
conf_data.set('XNVME_BE_LINUX_BLOCK_ZONED_ENABLED', is_linux ? cc.has_header('linux/blkzoned.h') : false)

conf_data.set('XNVME_BE_LINUX_LIBAIO_ENABLED', is_linux and get_option('with-libaio'))
conf_data.set('XNVME_BE_LINUX_LIBURING_ENABLED', is_linux and get_option('with-liburing'))

conf_data.set('XNVME_BE_LINUX_VFIO_ENABLED', is_linux and get_option('with-libvfn'))

conf_data.set('XNVME_BE_MACOS_ENABLED', is_darwin)

conf_data.set('XNVME_BE_FBSD_ENABLED', is_freebsd)
conf_data.set('XNVME_BE_POSIX_ENABLED', is_linux or is_freebsd or is_darwin)

conf_data.set('XNVME_BE_SPDK_ENABLED', (is_linux or is_freebsd) and get_option('with-spdk'))
conf_data.set('XNVME_BE_SPDK_TRANSPORT_PCIE_ENABLED', (is_linux or is_freebsd) and get_option('with-spdk'))
conf_data.set('XNVME_BE_SPDK_TRANSPORT_TCP_ENABLED', (is_linux or is_freebsd) and get_option('with-spdk'))
conf_data.set('XNVME_BE_SPDK_TRANSPORT_RDMA_ENABLED', (is_linux or is_freebsd) and get_option('with-spdk'))
conf_data.set('XNVME_BE_SPDK_TRANSPORT_FC_ENABLED', (is_linux or is_freebsd) and get_option('with-spdk'))

conf_data.set('XNVME_BE_ASYNC_ENABLED', true)
conf_data.set('XNVME_BE_ASYNC_EMU_ENABLED', get_option('async_emu'))
conf_data.set('XNVME_BE_ASYNC_THRPOOL_ENABLED', get_option('async_thrpool'))

conf = configure_file(
  configuration : conf_data,
  output : 'xnvme_config.h',
)
conf_inc = [ include_directories('.') ]
if is_windows
  conf_inc += [ include_directories('third-party'/'windows') ]
endif

# Provide configuration via header-file 'xnvme_config.h'
add_global_arguments(['-include', 'xnvme_config.h'], language: 'c')

# bash-completions: run the Makefile target 'make gen-man-pages' to update the completions
# TODO: run the generator-script as part of the meson-build-process for the individual cli-tools to
# avoid manual build of man-pages and to avoid storing autogenerated stuff in the repository
bash_completion_dep = dependency(
  'bash-completion',
  version: '>=2.0',
  required: get_option('bash_completion')
)
if bash_completion_dep.found()
  bash_completions_dir = bash_completion_dep.get_variable('completionsdir')
  message('Bash-completions: ' + bash_completions_dir)
  subdir('toolbox'/'bash_completion.d')
endif

# man-pages: run the Makefile target 'make gen-man-pages' to update the man-pages
# TODO: run the generator-script as part of the meson-build-process for the individual cli-tools to
# avoid manual build of man-pages and to avoid storing autogenerated stuff in the repository
if get_option('manpages')
  subdir('man')
endif

# Scripts
subdir('toolbox')

tb_library_bundler = files('toolbox'/'library_bundler.py')

#
# Third-party dependencies -- this is actually lib-specific... should probably be moved into
# 'lib/meson.build'?
#
thread_dep = dependency('threads')

fio_cfg_h = 'subprojects'/'fio'/'config-host.h'
fio_dep = dependency(
  'fio',
  required: get_option('with-fio')
)
# Fio Windows Posix Headers
if is_windows and get_option('with-fio')
    fio_winposix_inc = include_directories('subprojects'/'fio'/'os'/'windows'/'posix'/'include')
else
    fio_winposix_inc = include_directories()
endif

setupapi_dep = cc.find_library(
  'setupapi',
  has_headers: ['setupapi.h'],
  required: conf_data.get('XNVME_BE_WINDOWS_ENABLED'),
)

rt_dep = cc.find_library(
  'rt',
  required: is_darwin ? false : conf_data.get('XNVME_BE_POSIX_ENABLED')
)
if not cc.has_function('clock_gettime', prefix: '#include <time.h>', dependencies: rt_dep)
  error('clock_gettime not found')
endif

aio_dep = cc.find_library(
  'aio',
  has_headers: ['libaio.h'],
  required: conf_data.get('XNVME_BE_LINUX_LIBAIO_ENABLED'),
)

uring_dep = dependency(
  'liburing',
  version: '>=2.2',
  required: false,
)
if conf_data.get('XNVME_BE_LINUX_LIBURING_ENABLED') and not uring_dep.found()
  error('missing liburing >= 2.2; install it or point PKG_CONFIG_PATH to where it is located')
endif

math_dep = cc.find_library(
  'm',
  has_headers: ['math.h'],
  required: conf_data.get('XNVME_BE_SPDK_ENABLED'),
)

ssl_dep = dependency(
  is_centos7 ? 'openssl11' : 'openssl', version: '>=1.1.1',
  required: conf_data.get('XNVME_BE_SPDK_ENABLED'),
)

dlfcn_dep = cc.find_library(
  'dl',
  has_headers: ['dlfcn.h'],
  required: conf_data.get('XNVME_BE_SPDK_ENABLED'),
)

uuid_dep = cc.find_library(
  'uuid',
  dirs: is_freebsd ? [ '/usr/local/lib' ] : [],
  header_include_directories: is_freebsd ? [ include_directories('/usr/local/include') ] : [],
  has_headers: ['uuid/uuid.h'],
  required: conf_data.get('XNVME_BE_SPDK_ENABLED'),
)
numa_dep = cc.find_library(
  'numa',
  has_headers: ['numaif.h'],
  required: conf_data.get('XNVME_BE_SPDK_ENABLED') and is_linux,
)
execinfo_dep = cc.find_library(
  'execinfo',
  has_headers: ['execinfo.h'],
  required: conf_data.get('XNVME_BE_SPDK_ENABLED') and is_freebsd,
)
elf_dep = cc.find_library(
  'elf',
  has_headers: ['sys/elf_common.h'],
  required: conf_data.get('XNVME_BE_SPDK_ENABLED') and is_freebsd,
)
spdk_dep = dependency(
  'spdk',
  required: conf_data.get('XNVME_BE_SPDK_ENABLED')
)
corefoundation_dep = dependency(
  'appleframeworks',
  modules: 'CoreFoundation',
  required: is_darwin
)
iokit_dep = dependency(
  'appleframeworks',
  modules: 'IOKit',
  required: is_darwin
)
libvfn_dep = dependency(
  '_vfn',
  default_options: [
    'libnvme=disabled',
    'docs=disabled',
    'default_library=static',
  ],
  required: conf_data.get('XNVME_BE_LINUX_VFIO_ENABLED')
)

# Headers
subdir('include')

# Library source
subdir('lib')

# Tests, tools, fio io-engine, and code examples
if get_option('tests')
  subdir('tests')
endif
if get_option('tools')
  subdir('tools')
endif
if get_option('tools') and get_option('with-fio')
  subdir('tools/fio-engine')
endif
if get_option('examples')
  subdir('examples')
endif
